<template>
  <div class="digital-human-generate">
    <!-- 使用引导提示 -->
    <div v-if="showGuide" class="guide-tip">
      <div class="guide-content">
        <div class="guide-icon">💡</div>
        <div class="guide-text">
          <strong>使用步骤：</strong>上传视频或选择数字人 → 输入口播文案或上传录音文件 → 选择音色 → 生成视频
        </div>
      </div>
    </div>

    <!-- 左侧内容区域 -->
    <div class="left-content">
      <!-- 上半部分：个人数字人管理区域 -->
      <div class="top-section">
        <!-- 个人数字人创建和管理 -->
        <div class="my-avatars-section">
          <div class="section-header">
            <h2 class="section-title">生成数字人</h2>
            <h2 class="section-title records-title" @click="handleGoToRecords">
              <el-icon><Document /></el-icon>
              生成记录
            </h2>
          </div>
          
          <!-- 我的数字人列表 -->
          <div class="my-avatars-grid">
            <!-- 只有当有我的数字人时才显示 -->
            <el-card 
              v-for="avatar in myAvatars" 
              :key="avatar.id" 
              class="avatar-card my-avatar-card"
              shadow="hover"
              @click="handleSelectAvatar(avatar)"
            >
              <img :src="avatar.coverUrl" class="avatar-image" />
              <div class="avatar-info">
                <div class="avatar-name">{{ avatar.name }}</div>
                <div class="avatar-actions">
                  <el-button type="primary" link @click.stop="handleEditAvatar(avatar)">编辑</el-button>
                  <el-button type="danger" link @click.stop="handleDeleteAvatar(avatar)">删除</el-button>
                </div>
              </div>
            </el-card>
            
            <!-- 创建新数字人的卡片 -->
            <div class="upload-wrapper">
              <input
                type="file"
                accept="video/mp4,video/mov,video/quicktime,video/x-msvideo,video/x-ms-wmv,video/webm"
                class="file-input"
                ref="fileInputRef"
                @change="handleVideoSelect"
              />
              <el-card 
                class="avatar-card create-avatar-card" 
                shadow="hover" 
                @click="handleCardClick"
              >
                <div class="create-avatar-content" v-if="!previewVideo">
                  <el-icon size="48" class="create-icon"><Plus /></el-icon>
                  <div class="create-text">创建新数字人</div>
                  <div class="create-hint">支持 MP4、MOV、AVI 等格式</div>
                </div>
                <div class="preview-content" v-else>
                  <video 
                    ref="videoPreviewRef"
                    class="preview-video"
                    :src="previewVideo.url"
                    muted
                    loop
                    @mouseover="playPreview"
                    @mouseout="pausePreview"
                  ></video>
                  <div class="preview-overlay">
                    <div class="preview-actions">
                      <el-button type="danger" @click.stop="resetUpload">重新上传</el-button>
                    </div>
                  </div>
                </div>
              </el-card>
            </div>
          </div>
        </div>
      </div>

      <!-- 下半部分：公共数字人展示区域 -->
      <div class="bottom-section">
        <div class="public-avatars-section">
            <h2 class="section-title">公共数字人库</h2>
          
          <!-- 人种标签 -->
          <div class="ethnicity-section">
            <h4 class="section-subtitle">人种筛选</h4>
            <div class="ethnicity-list">
              <!-- 如果正在加载或人种列表为空，显示加载中 -->
              <div v-if="ethnicityLoading || ethnicityList.length === 0" class="category-item disabled">
                {{ ethnicityLoading ? '加载中...' : '暂无人种分类' }}
              </div>
              <!-- 所有分类选项 -->
              <div 
                v-if="ethnicityList.length > 0"
                class="category-item"
                :class="{ active: activeEthnicity === 'all' }"
                @click="handleEthnicityChange('all')"
              >
                所有
              </div>
              <!-- 人种列表 -->
              <div 
                v-for="ethnicity in ethnicityList" 
                :key="ethnicity.ethnicityId" 
                class="category-item"
                :class="{ active: activeEthnicity === ethnicity.ethnicityId }"
                @click="handleEthnicityChange(ethnicity.ethnicityId)"
              >
                {{ ethnicity.ethnicityName }}
              </div>
            </div>
          </div>
          
          <!-- 公共数字人网格 -->
          <div class="public-avatars-grid" ref="publicAvatarsRef" @scroll="handlePublicAvatarsScroll">
            <div
              v-for="avatar in filteredPublicList"
              :key="avatar.aiavatarId"
              :data-avatar-id="avatar.aiavatarId"
              class="avatar-item"
              @click="handlePlayPreview(avatar)"
              @mouseenter="handleMouseEnter(avatar)"
              @mouseleave="handleMouseLeave(avatar)"
            >
              <!-- 默认显示图片 -->
              <img 
                v-show="!avatar.isHovering" 
                :src="avatar.coverUrl" 
                class="avatar-image" 
              />
              <!-- 悬停时显示视频 -->
              <video 
                v-show="avatar.isHovering"
                v-if="avatar.previewVideoUrl"
                :src="avatar.previewVideoUrl" 
                class="avatar-video"
                muted
                loop
                preload="metadata"
                @loadeddata="handleVideoLoaded(avatar)"
              />
            </div>
            <div v-if="publicLoading" class="loading-more">
              <el-icon class="is-loading"><Loading /></el-icon>
              <span>加载中...</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 右侧脚本编辑面板 -->
    <div class="script-panel">
      <div class="script-header">
        <h3>脚本编辑</h3>
        <el-button-group>
          <el-button 
            :type="scriptMode === 'tts' ? 'primary' : 'default'" 
            @click="scriptMode = 'tts'"
          >
            文本转语音
          </el-button>
          <el-button 
            :type="scriptMode === 'audio' ? 'primary' : 'default'" 
            @click="handleSwitchToAudio"
          >
            导入音频
          </el-button>
        </el-button-group>
      </div>
      
      <!-- 文本转语音模式 -->
      <template v-if="scriptMode === 'tts'">
        <el-input
          type="textarea"
          :rows="24"
          placeholder="在此输入需要AI配音的文本..."
          v-model="scriptText"
          maxlength="8000"
          show-word-limit
          class="script-textarea"
        />
      </template>

      <!-- 导入音频模式 -->
      <template v-else>
        <div class="audio-upload-section">
          <input
            type="file"
            accept="audio/*"
            class="file-input"
            ref="audioInputRef"
            @change="handleAudioSelect"
          />
          <div v-if="!previewAudio" class="upload-placeholder" @click="triggerAudioSelect">
            <el-icon size="32"><Upload /></el-icon>
            <div class="upload-text">点击上传音频文件</div>
            <div class="upload-hint">支持 MP3, WAV 等格式</div>
          </div>
          <div v-else class="audio-preview">
            <div class="audio-info">
              <el-icon><Document /></el-icon>
              <span class="audio-name">{{ previewAudio.fileName }}</span>
            </div>
            <audio controls :src="previewAudio.url" class="audio-player"></audio>
            <div class="audio-actions">
              <el-button type="danger" @click="resetAudioUpload">重新上传</el-button>
            </div>
          </div>
        </div>
      </template>

      <div class="script-footer">
        <el-select
          v-if="scriptMode === 'tts'"
          v-model="selectedSpeaker"
          placeholder="选择AI音色"
          class="voice-select"
          @click="showVoiceDialog = true"
        >
          <el-option
            :value="selectedSpeaker"
            :label="selectedSpeaker ? selectedSpeaker.voiceName : '选择AI音色'"
          />
        </el-select>
        
        <el-button type="primary" class="generate-btn" @click="handleGenerateVideo">
          <el-icon><VideoPlay /></el-icon>
          生成视频
          <span class="points-text">3积分</span>
        </el-button>
      </div>
    </div>

    <!-- 视频预览弹窗 -->
    <el-dialog 
      v-model="showVideoDialog" 
      :title="currentVideo?.aiavatarName || '数字人预览'" 
      width="900px" 
      center
      class="video-dialog"
      @close="handleVideoDialogClose"
    >
      <div class="video-preview-container">
        <div class="video-wrapper">
          <video 
            v-if="currentVideo" 
            ref="previewVideoRef"
            :src="currentVideo.previewVideoUrl" 
            controls 
            autoplay 
            class="preview-video"
            @loadstart="handleVideoLoadStart"
            @canplay="handleVideoCanPlay"
          >
            您的浏览器不支持视频播放
          </video>
          <div v-if="videoLoading" class="video-loading">
            <el-icon class="is-loading"><Loading /></el-icon>
            <span>视频加载中...</span>
          </div>
        </div>
        <div class="video-info-card">
          <div class="info-header">
            <h3>{{ currentVideo?.aiavatarName }}</h3>
            <el-tag :type="currentVideo?.gender === 'male' ? 'primary' : 'danger'" size="small">
              {{ currentVideo?.gender === 'male' ? '男性' : '女性' }}
            </el-tag>
          </div>
          <div class="info-content">
            <div class="info-item" v-if="currentVideo?.ethnicities?.length">
              <span class="label">种族：</span>
              <span class="value">{{ currentVideo.ethnicities.map(e => e.ethnicityName).join(', ') }}</span>
            </div>
            <div class="info-item" v-if="currentVideo?.voiceoverIdDefault">
              <span class="label">默认语音ID：</span>
              <span class="value">{{ currentVideo.voiceoverIdDefault }}</span>
            </div>
            <div class="info-item">
              <span class="label">数字人ID：</span>
              <span class="value">{{ currentVideo?.aiavatarId }}</span>
            </div>
          </div>
          <div class="dialog-actions">
            <el-button @click="showVideoDialog = false">关闭</el-button>
            <el-button type="primary" @click="handleUseAvatar(currentVideo)">使用此数字人</el-button>
          </div>
        </div>
      </div>
    </el-dialog>

    <!-- 音色选择弹窗 -->
    <el-dialog
      v-model="showVoiceDialog"
      title="选择AI音色"
      width="80%"
      class="voice-dialog"
    >
      <div class="voice-filter">
        <el-radio-group v-model="genderFilter" class="filter-item" @change="handleVoiceFilterChange">
          <el-radio-button label="">全部</el-radio-button>
          <el-radio-button label="male">男声</el-radio-button>
          <el-radio-button label="female">女声</el-radio-button>
        </el-radio-group>
        <el-radio-group v-model="ageFilter" class="filter-item" @change="handleVoiceFilterChange">
          <el-radio-button label="">全部年龄</el-radio-button>
          <el-radio-button label="Young">青年</el-radio-button>
          <el-radio-button label="Middle Age">中年</el-radio-button>
          <el-radio-button label="Old">老年</el-radio-button>
        </el-radio-group>
        <el-select v-model="languageFilter" placeholder="全部语言" class="filter-item language-select" style="width: 220px;" @change="handleVoiceFilterChange">
          <el-option label="全部" value="" />
          <el-option label="简体中文 (Simplified Chinese)" value="zh-CN" />
          <el-option label="English" value="en" />
          <el-option label="Arabic (العربية)" value="ar" />
          <el-option label="Bulgarian (Български)" value="bg" />
          <el-option label="Croatian (Hrvatski)" value="hr" />
          <el-option label="Czech (Čeština)" value="cs" />
          <el-option label="Danish (Dansk)" value="da" />
          <el-option label="Dutch (Nederlands)" value="nl" />
          <el-option label="Filipino (Filipino)" value="fil" />
          <el-option label="Finnish (Suomi)" value="fi" />
          <el-option label="French (Français)" value="fr" />
          <el-option label="German (Deutsch)" value="de" />
          <el-option label="Greek (Ελληνικά)" value="el" />
          <el-option label="Hindi (हिन्दी)" value="hi" />
          <el-option label="Hungarian (Magyar)" value="hu" />
          <el-option label="Indonesian (Bahasa Indonesia)" value="id" />
          <el-option label="Italian (Italiano)" value="it" />
          <el-option label="Japanese (日本語)" value="ja" />
          <el-option label="Korean (한국어)" value="ko" />
          <el-option label="Malay (Bahasa Melayu)" value="ms" />
          <el-option label="Norwegian (Norsk)" value="nb" />
          <el-option label="Polish (Polski)" value="pl" />
          <el-option label="Portuguese (Português)" value="pt" />
          <el-option label="Romanian (Română)" value="ro" />
          <el-option label="Russian (Русский)" value="ru" />
          <el-option label="Slovak (Slovenčina)" value="sk" />
          <el-option label="Spanish (Español)" value="es" />
          <el-option label="Swedish (Svenska)" value="sv" />
          <el-option label="Traditional Chinese (繁體中文)" value="zh-Hant" />
          <el-option label="Turkish (Türkçe)" value="tr" />
          <el-option label="Ukrainian (Українська)" value="uk" />
          <el-option label="Vietnamese (Tiếng Việt)" value="vi" />
        </el-select>
      </div>
      
      <div class="voice-grid" ref="voiceGridRef" @scroll="handleVoiceScroll">
        <div
          v-for="voice in voiceList"
          :key="voice.voiceId"
          class="voice-card"
          :class="{ active: selectedSpeaker?.voiceId === voice.voiceId }"
          @click="handleSelectVoice(voice)"
        >
          <div class="voice-info">
            <div class="voice-name">{{ voice.voiceName }}</div>
            <div class="voice-tags">
              <el-tag size="small" :type="voice.gender === 'male' ? 'info' : 'danger'">
                {{ voice.gender === 'male' ? '男声' : '女声' }}
              </el-tag>
              <el-tag size="small" type="warning">{{ voice.age }}</el-tag>
              <el-tag size="small" type="success">{{ voice.accent }}</el-tag>
            </div>
          </div>
          <div class="voice-preview">
            <el-button 
              type="primary" 
              size="small"
              class="preview-btn" 
              @click.stop="playVoiceDemo(voice)"
            >
              <el-icon><VideoPlay /></el-icon>
              试听
            </el-button>
          </div>
        </div>
        <div v-if="voiceLoading" class="loading-more">
          <el-icon class="is-loading"><Loading /></el-icon>
          <span>加载中...</span>
        </div>
      </div>
      
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="showVoiceDialog = false">取消</el-button>
          <el-button type="primary" @click="confirmVoiceSelection">
            确定
          </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted, computed, nextTick, onUnmounted, watch } from 'vue'
import { Plus, Loading, VideoPlay, Upload, Document, List } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import { API_CONFIG, apiRequest } from '../../config/api.js'
import { useRouter, useRoute } from 'vue-router'

// 获取 router 和 route 实例
const router = useRouter()
const route = useRoute()

// 响应式数据
const myAvatars = ref([])
const publicList = ref([])
const scriptText = ref('')
const selectedSpeaker = ref('')
const subtitleStyle = ref('')
const scriptMode = ref('tts')
const voiceList = ref([])

// 引导提示
const showGuide = ref(true)

// 人种相关
const ethnicityList = ref([])
const activeEthnicity = ref('')
const ethnicityLoading = ref(false)

// 视频预览相关
const showVideoDialog = ref(false)
const currentVideo = ref(null)
const videoLoading = ref(false)
const previewVideoRef = ref(null)

// 文件输入框引用
const fileInputRef = ref(null)
const videoPreviewRef = ref(null)
const previewVideo = ref(null)
const audioInputRef = ref(null)
const previewAudio = ref(null)

// 音色选择相关
const showVoiceDialog = ref(false)
const genderFilter = ref('')
const ageFilter = ref('')
const languageFilter = ref('zh-CN')
const audioPlayer = ref(new Audio())

// 分页相关
const publicAvatarsRef = ref(null)
const voiceGridRef = ref(null)
const publicLoading = ref(false)
const voiceLoading = ref(false)
const publicPageNo = ref(1)
const voicePageNo = ref(1)
const publicHasMore = ref(true)
const voiceHasMore = ref(true)
const pageSize = 20

// 计算属性：过滤后的公共数字人列表
const filteredPublicList = computed(() => {
  return publicList.value
})



// 获取我的数字人列表
async function getMyAvatars() {
  try {
    const response = await apiRequest(API_CONFIG.ENDPOINTS.GET_MY_AVATARS, {
      method: 'GET'
    })
    if (response && response.code === 200 && response.data) {
      myAvatars.value = response.data
    }
  } catch (e) {
    console.error('获取我的数字人列表失败:', e)
    // 不使用默认数据，保持空数组
    myAvatars.value = []
  }
}

// 获取人种列表
async function getEthnicityList() {
  try {
    ethnicityLoading.value = true
    const params = new URLSearchParams({
      scene: 'video_avatar'
    })
    
    const response = await apiRequest(`${API_CONFIG.ENDPOINTS.GET_ETHNICITY_LIST}?${params.toString()}`, {
      method: 'GET'
    })
    
    if (response && response.code === 200 && response.result && response.result.data) {
      // 英文到中文的翻译映射
      const ethnicityTranslations = {
        'Black or African American': '非洲裔美国人',
        'White (Western European)': '西欧白人',
        'White (Eastern European)': '东欧白人',
        'Hispanic or Latino': '西班牙裔/拉丁裔',
        'Middle Eastern or North African': '中东/北非',
        'East Asian': '东亚',
        'Southeast Asian': '东南亚',
        'South Asian': '南亚'
      }
      
      // 处理数据并翻译为中文
      ethnicityList.value = response.result.data.map(ethnicity => ({
        ...ethnicity,
        ethnicityName: ethnicityTranslations[ethnicity.ethnicityName] || ethnicity.ethnicityName
      }))
      
      // 设置默认选中"所有"
      if (!activeEthnicity.value) {
        activeEthnicity.value = 'all'
      }
    }
  } catch (error) {
    console.error('获取人种列表失败:', error)
    ElMessage.warning('获取人种列表失败')
  } finally {
    ethnicityLoading.value = false
  }
}

// 获取公共数字人列表
async function getPublicAvatars(isLoadMore = false) {
  if (!isLoadMore) {
    // 重置为第一页
    publicPageNo.value = 1
    publicHasMore.value = true
    publicList.value = []
    // 清除 URL 中的页码参数
    router.replace({
      query: {}
    })
  }

  if (!publicHasMore.value || publicLoading.value) return

  try {
    publicLoading.value = true
    const params = new URLSearchParams({
      pageNo: String(publicPageNo.value),
      pageSize: String(pageSize)
    })
    
    // 添加人种参数
    if (activeEthnicity.value && activeEthnicity.value !== 'all') {
      params.append('ethnicityIdList', activeEthnicity.value)
      params.append('scene', 'video_avatar')
    }
    
    const response = await apiRequest(`${API_CONFIG.ENDPOINTS.GET_AVATAR_LIST}?${params.toString()}`, {
      method: 'GET'
    })

    if (response?.code === 200 && response.data) {
      const { data, total } = response.data
      const newList = data.map(avatar => ({
        ...avatar,
        isHovering: false
      }))
      
      if (isLoadMore) {
        publicList.value = [...publicList.value, ...newList]
      } else {
        publicList.value = newList
      }

      publicHasMore.value = publicList.value.length < total
      
      if (publicHasMore.value) {
        publicPageNo.value++
      }
    }
  } catch (error) {
    console.error('获取公共数字人列表失败:', error)
    ElMessage.warning('获取公共数字人列表失败')
  } finally {
    publicLoading.value = false
  }
}

// 获取音色列表
async function getVoiceList(isLoadMore = false) {
  if (!isLoadMore) {
    voicePageNo.value = 1
    voiceHasMore.value = true
    voiceList.value = []
  }
  if (!voiceHasMore.value || voiceLoading.value) return
  try {
    voiceLoading.value = true
    const params = {
        pageNo: voicePageNo.value,
        pageSize
      }
    if (genderFilter.value) params.gender = genderFilter.value
    if (ageFilter.value) params.age = ageFilter.value
    if (languageFilter.value) params.language = languageFilter.value
    const response = await apiRequest('/aiAvatar/voiceList', {
      method: 'GET',
      params
    })
    if (response && response.code === 200 && response.data) {
      const { data, total } = response.data
      if (isLoadMore) {
        voiceList.value = [...voiceList.value, ...data]
      } else {
        voiceList.value = data
      }
      voiceHasMore.value = voiceList.value.length < total
      if (voiceHasMore.value) {
        voicePageNo.value++
      }
    }
  } catch (error) {
    console.error('获取AI音色列表失败:', error)
    ElMessage.warning('获取AI音色列表失败')
  } finally {
    voiceLoading.value = false
  }
}

// 事件处理函数
async function handleCreateDigitalHuman() {
  const token = localStorage.getItem('token')
  if (!token) {
    ElMessage.error('请先登录！')
    return
  }
  try {
    const data = await apiRequest(API_CONFIG.ENDPOINTS.GET_UPLOAD_CREDENTIAL, {
      method: 'GET'
    })
    ElMessage.success('获取上传凭证成功！')
    console.log('上传凭证:', data)
    
    // TODO: 这里应该打开上传数字人的弹窗或页面
    // 上传成功后调用 getMyAvatars() 刷新列表
    ElMessage.info('请实现数字人上传功能，上传成功后会显示在"我的数字人"列表中')
    
  } catch (e) {
    ElMessage.error('获取上传凭证失败')
    console.error('Error:', e)
  }
}

function handleSelectAvatar(avatar) {
  ElMessage.success(`已选择数字人：${avatar.name}`)
}

function handleEditAvatar(avatar) {
  ElMessage.info(`编辑数字人：${avatar.name}`)
}

function handleDeleteAvatar(avatar) {
  ElMessageBox.confirm(
    `确定要删除数字人"${avatar.name}"吗？`,
    '删除确认',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }
  ).then(() => {
    ElMessage.success('删除成功')
  }).catch(() => {})
}

function handlePlayPreview(avatar) {
  currentVideo.value = avatar
  showVideoDialog.value = true
  videoLoading.value = true
  console.log('播放预览视频:', avatar.aiavatarName, avatar.previewVideoUrl)
}

function handleVideoLoadStart() {
  videoLoading.value = true
}

function handleVideoCanPlay() {
  videoLoading.value = false
}

function handleUseAvatar(avatar) {
  ElMessage.success(`已选择使用数字人：${avatar.aiavatarName}`)
  handleVideoDialogClose()
  showVideoDialog.value = false
}

// 处理视频预览弹窗关闭
function handleVideoDialogClose() {
  // 停止视频播放
  if (previewVideoRef.value) {
    previewVideoRef.value.pause()
    previewVideoRef.value.currentTime = 0
  }
}

// 处理人种切换
function handleEthnicityChange(ethnicityId) {
  console.log('切换人种:', ethnicityId)
  activeEthnicity.value = ethnicityId
  // 重新获取该人种下的数字人列表
  getPublicAvatars()
}

// 处理视频生成
async function handleGenerateVideo() {
  if (scriptMode.value === 'tts' && !scriptText.value.trim()) {
    ElMessage.warning('请输入脚本内容')
    return
  }

  if (scriptMode.value === 'audio' && !previewAudio.value) {
    ElMessage.warning('请上传音频文件')
    return
  }

  // 检查数字人来源
  const isUploadedVideo = previewVideo.value // 是否是上传的视频
  if (!isUploadedVideo && !currentVideo.value) {
    ElMessage.warning('请选择一个数字人或上传视频')
    return
  }

  const loading = ElLoading.service({
    lock: true,
    text: '正在提交生成任务...',
    background: 'rgba(0, 0, 0, 0.7)'
  })

  try {
    const params = {
      avatarSourceFrom: isUploadedVideo ? 0 : 1, // 0-用户上传视频，1-公模数字人
      audioSourceFrom: scriptMode.value === 'tts' ? 1 : 0, // 0-用户上传音频，1-文本转语音
    }

    // 根据数字人来源设置参数
    if (isUploadedVideo) {
      params.videoFileId = previewVideo.value.fileId
    } else {
      params.aiAvatarId = currentVideo.value.aiavatarId
    }

    // 根据音频来源设置参数
    if (scriptMode.value === 'tts') {
      params.ttsText = scriptText.value
      // 如果是公模数字人且没有选择音色，则使用默认音色
      if (selectedSpeaker.value?.voiceId || !params.aiAvatarId) {
        params.voiceoverId = selectedSpeaker.value?.voiceId
      }
    } else {
      params.audioFileId = previewAudio.value.fileId
    }


    const response = await apiRequest('/aiAvatar/videoAvatarSubmit', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(params)
    })

    if (response.code === 200) {
      ElMessage.success('任务提交成功')
      // 跳转到生成列表页面
      router.push('/digital-human/list')
    } else {
      throw new Error(response.message || '提交失败')
    }
  } catch (error) {
    console.error('生成失败:', error)
    ElMessage.error(error.message || '生成失败，请重试')
  } finally {
    loading.close()
  }
}

function handleMouseEnter(avatar) {
  avatar.isHovering = true
  // 延迟一点时间确保DOM更新完成
  nextTick(() => {
    const cardElement = document.querySelector(`[data-avatar-id="${avatar.aiavatarId}"]`)
    const videoElement = cardElement?.querySelector('video')
    if (videoElement && avatar.isHovering) {
      videoElement.currentTime = 0
      videoElement.play().catch(e => {
        console.log('视频自动播放失败:', e)
      })
    }
  })
}

function handleMouseLeave(avatar) {
  avatar.isHovering = false
  // 停止视频播放并重置到开始位置
  const cardElement = document.querySelector(`[data-avatar-id="${avatar.aiavatarId}"]`)
  const videoElement = cardElement?.querySelector('video')
  if (videoElement) {
    videoElement.pause()
    videoElement.currentTime = 0
  }
}

function handleVideoLoaded(avatar) {
  console.log('视频加载完成:', avatar.aiavatarName)
}

// 处理卡片点击
function handleCardClick() {
  if (!previewVideo.value) {
    triggerFileSelect()
  }
}

// 触发文件选择
function triggerFileSelect() {
  fileInputRef.value?.click()
}

// 播放预览视频
function playPreview() {
  if (videoPreviewRef.value) {
    videoPreviewRef.value.play()
  }
}

// 暂停预览视频
function pausePreview() {
  if (videoPreviewRef.value) {
    videoPreviewRef.value.pause()
  }
}

// 重置上传
function resetUpload() {
  previewVideo.value = null
  if (fileInputRef.value) {
    fileInputRef.value.value = ''
  }
}


// 处理视频选择
async function handleVideoSelect(event) {
  const file = event.target.files?.[0]
  if (!file) {
    return
  }

  // 支持多种视频格式
  const supportedVideoTypes = [
    'video/mp4',
    'video/mov',
    'video/quicktime',
    'video/x-msvideo',
    'video/x-ms-wmv',
    'video/webm'
  ]
  
  if (!supportedVideoTypes.includes(file.type)) {
    ElMessage.error('请选择支持的视频格式：MP4、MOV、AVI、WMV、WebM 等')
    return
  }

  // 如果已经有预览视频，先重置
  if (previewVideo.value) {
    resetUpload()
  }

  // 显示加载中
  const loading = ElLoading.service({
    lock: true,
    text: '正在上传视频...',
    background: 'rgba(0, 0, 0, 0.7)'
  })

  try {
    // 1. 获取上传凭证
    const response = await apiRequest(API_CONFIG.ENDPOINTS.GET_UPLOAD_CREDENTIAL, {
      method: 'GET'
    })

    if (response.code !== 200 || !response.data) {
      throw new Error('获取上传凭证失败')
    }

    const { uploadUrl, fileId, fileName } = response.data

    // 2. 上传视频到 S3
    const uploadResponse = await fetch(uploadUrl, {
      method: 'PUT',
      body: file,
      headers: {
        'Content-Type': file.type
      }
    })

    if (!uploadResponse.ok) {
      throw new Error('视频上传失败')
    }

    // 设置预览
    previewVideo.value = {
      url: URL.createObjectURL(file),
      fileId,
      fileName
    }

    ElMessage.success('视频上传成功')

  } catch (error) {
    console.error('上传失败:', error)
    ElMessage.error(error.message || '上传失败，请重试')
    resetUpload()
  } finally {
    loading.close()
  }
}

// 切换到音频模式
function handleSwitchToAudio() {
  scriptMode.value = 'audio'
  scriptText.value = '' // 清空文本
}

// 跳转到生成记录页面
function handleGoToRecords() {
  router.push('/digital-human/list')
}

// 触发音频选择
function triggerAudioSelect() {
  audioInputRef.value?.click()
}

// 重置音频上传
function resetAudioUpload() {
  if (previewAudio.value?.url) {
    URL.revokeObjectURL(previewAudio.value.url)
  }
  previewAudio.value = null
  if (audioInputRef.value) {
    audioInputRef.value.value = ''
  }
}

// 处理音频选择
async function handleAudioSelect(event) {
  const file = event.target.files?.[0]
  if (!file) return

  // 检查文件类型
  if (!file.type.startsWith('audio/')) {
    ElMessage.error('请选择音频文件')
    return
  }

  // 获取文件后缀
  const extension = file.name.split('.').pop()?.toLowerCase()
  if (!extension) {
    ElMessage.error('无法识别文件格式')
    return
  }

  // 支持的文件格式映射
  const supportedFormats = {
    'mp4': 'mp4',
    'mov': 'mov',
    'png': 'png',
    'jpg': 'jpg',
    'jpeg': 'jpeg',
    'bmp': 'bmp',
    'webp': 'webp',
    'mp3': 'mp3',
    'wav': 'wav',
    'm4a': 'm4a'
  }

  // 检查是否是支持的格式
  if (!supportedFormats[extension]) {
    ElMessage.error('不支持的文件格式，请上传 mp3、wav、m4a 格式的音频文件')
    return
  }

  // 如果已经有预览音频，先重置
  if (previewAudio.value) {
    resetAudioUpload()
  }

  // 显示加载中
  const loading = ElLoading.service({
    lock: true,
    text: '正在上传音频...',
    background: 'rgba(0, 0, 0, 0.7)'
  })

  try {
    // 1. 获取上传凭证
    const params = new URLSearchParams({
      format: supportedFormats[extension]
    })
    const response = await apiRequest(`${API_CONFIG.ENDPOINTS.GET_UPLOAD_CREDENTIAL}?${params.toString()}`, {
      method: 'GET'
    })

    if (response.code !== 200 || !response.data) {
      throw new Error('获取上传凭证失败')
    }

    const { uploadUrl, fileId, fileName } = response.data

    // 2. 上传音频到 S3
    const uploadResponse = await fetch(uploadUrl, {
      method: 'PUT',
      body: file,
      headers: {
        'Content-Type': file.type
      }
    })

    if (!uploadResponse.ok) {
      throw new Error('音频上传失败')
    }

    // 设置预览
    previewAudio.value = {
      url: URL.createObjectURL(file),
      fileId,
      fileName: file.name,
      type: file.type,
      format: supportedFormats[extension]
    }

    ElMessage.success('音频上传成功')

  } catch (error) {
    console.error('上传失败:', error)
    ElMessage.error(error.message || '上传失败，请重试')
    resetAudioUpload()
  } finally {
    loading.close()
  }
}

// 播放音色示例
function playVoiceDemo(voice) {
  if (audioPlayer.value.src === voice.demoAudioUrl) {
    if (audioPlayer.value.paused) {
      audioPlayer.value.play()
    } else {
      audioPlayer.value.pause()
    }
  } else {
    audioPlayer.value.src = voice.demoAudioUrl
    audioPlayer.value.play()
  }
}

// 选择音色
function handleSelectVoice(voice) {
  selectedSpeaker.value = voice
}

// 确认音色选择
function confirmVoiceSelection() {
  if (selectedSpeaker.value) {
    showVoiceDialog.value = false
  } else {
    ElMessage.warning('请选择一个音色')
  }
}

// 组件卸载时清理
onUnmounted(() => {
  if (previewVideo.value?.url) {
    URL.revokeObjectURL(previewVideo.value.url)
  }
  if (previewAudio.value?.url) {
    URL.revokeObjectURL(previewAudio.value.url)
  }
  audioPlayer.value.pause()
  audioPlayer.value.src = ''
})

// 页面加载时获取数据
onMounted(() => {
  // getMyAvatars() // 不在页面加载时获取，只有用户上传数字人后才显示
  getEthnicityList() // 获取人种列表
  getPublicAvatars() // 确保数字人列表能正常显示
  getVoiceList() // 添加获取音色列表的调用
})

// 处理公共数字人列表滚动
function handlePublicAvatarsScroll(e) {
  const { scrollHeight, scrollTop, clientHeight } = e.target
  // 滚动到底部时加载更多
  if (scrollHeight - scrollTop - clientHeight < 50 && !publicLoading.value && publicHasMore.value) {
    getPublicAvatars(true)
  }
}

// 处理音色列表滚动
function handleVoiceScroll(e) {
  const { scrollHeight, scrollTop, clientHeight } = e.target
  // 滚动到底部时加载更多
  if (scrollHeight - scrollTop - clientHeight < 50) {
    getVoiceList(true)
  }
}

// 监听人种变化
watch(activeEthnicity, (newEthnicityId) => {
  if (newEthnicityId) {
  getPublicAvatars()
  }
})

// 监听弹窗关闭
watch(showVoiceDialog, (newVal) => {
  if (!newVal) {
    // 弹窗关闭时停止音频播放
    audioPlayer.value.pause()
    audioPlayer.value.currentTime = 0
  } else {
    // 弹窗打开时，强制修复按钮样式
    nextTick(() => {
      fixRadioButtonStyles()
    })
  }
})

// 强制修复单选按钮样式的函数
function fixRadioButtonStyles() {
  const radioButtons = document.querySelectorAll('.voice-dialog .el-radio-button__inner')
  radioButtons.forEach(button => {
    // 强制设置样式
    button.style.setProperty('font-size', '14px', 'important')
    button.style.setProperty('transform', 'none', 'important')
    button.style.setProperty('scale', '1', 'important')
    button.style.setProperty('zoom', '1', 'important')
    button.style.setProperty('padding', '10px 20px', 'important')
    button.style.setProperty('line-height', '1.4', 'important')
    button.style.setProperty('width', 'auto', 'important')
    button.style.setProperty('height', 'auto', 'important')
    
    // 监听所有可能触发变化的事件
    button.addEventListener('click', () => {
      setTimeout(() => fixButtonStyle(button), 0)
    })
    button.addEventListener('mouseenter', () => {
      setTimeout(() => fixButtonStyle(button), 0)
    })
    button.addEventListener('mouseleave', () => {
      setTimeout(() => fixButtonStyle(button), 0)
    })
    button.addEventListener('focus', () => {
      setTimeout(() => fixButtonStyle(button), 0)
    })
  })
}

// 修复单个按钮样式
function fixButtonStyle(button) {
  button.style.setProperty('font-size', '14px', 'important')
  button.style.setProperty('transform', 'none', 'important')
  button.style.setProperty('scale', '1', 'important')
  button.style.setProperty('zoom', '1', 'important')
  button.style.setProperty('padding', '10px 20px', 'important')
  button.style.setProperty('line-height', '1.4', 'important')
}

// 处理音色筛选
function handleVoiceFilterChange() {
  getVoiceList(false)
  // 筛选后重新修复样式
  nextTick(() => {
    setTimeout(fixRadioButtonStyles, 100)
  })
}

// 监听路由参数变化
watch(
  () => route.query.pageNo,
  (newPageNo) => {
    if (newPageNo && Number(newPageNo) !== publicPageNo.value) {
      getPublicAvatars()
    }
  }
)
</script>

<style scoped>
:deep(body) {
  overflow: hidden;
}

.digital-human-generate {
  min-height: 100vh;
  background: #18181c;
  padding: 24px;
  display: flex;
  gap: 32px;
  box-sizing: border-box;
  overflow: auto;
  position: relative;
}

.guide-tip {
  position: absolute;
  top: 24px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  background: linear-gradient(135deg, #409eff, #66b1ff);
  border-radius: 12px;
  padding: 12px 24px;
  box-shadow: 0 8px 32px rgba(64, 158, 255, 0.3);
  animation: slideDown 0.5s ease-out;
  min-width: 600px;
}

.guide-content {
  display: flex;
  align-items: center;
  gap: 12px;
  color: white;
}

.guide-icon {
  font-size: 18px;
}


.guide-text {
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  flex: 1;
}



@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}

/* 左侧内容区域 */
.left-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 32px;
  min-width: 0;
}

/* 上半部分样式 */
.top-section {
  background: #23232a;
  border-radius: 20px;
  padding: 32px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
  border: 1px solid #2a2a2a;
}

.my-avatars-section .section-header {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 32px;
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 1px solid #2a2a2a;
}

.section-title {
  font-size: 24px;
  font-weight: 600;
  color: #fff;
  margin: 0;
  letter-spacing: 0.5px;
}

.records-title {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  transition: all 0.3s ease;
  color: #409eff;
  position: relative;
  padding: 4px 12px;
  border-radius: 6px;
  background: rgba(64, 158, 255, 0.1);
  border: 1px solid rgba(64, 158, 255, 0.3);
}

.records-title:hover {
  color: #66b1ff;
  background: rgba(64, 158, 255, 0.2);
  border-color: rgba(64, 158, 255, 0.5);
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
}

.records-title::after {
  content: '';
  position: absolute;
  bottom: -2px;
  left: 12px;
  right: 12px;
  height: 2px;
  background: #409eff;
  transform: scaleX(0);
  transition: transform 0.3s ease;
}

.records-title:hover::after {
  transform: scaleX(1);
}

.create-btn {
  background: linear-gradient(45deg, #409eff, #764ba2);
  border: none;
  border-radius: 12px;
  padding: 12px 24px;
  font-weight: 600;
  color: #fff;
  box-shadow: 0 4px 15px rgba(64, 158, 255, 0.4);
  transition: all 0.3s ease;
}

.create-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(64, 158, 255, 0.6);
}

.my-avatars-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 16px;
}

.avatar-card {
  background: #23232a;
  border-radius: 16px;
  overflow: hidden;
  transition: all 0.3s ease;
  cursor: pointer;
  border: none;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}

.avatar-card:hover {
  /* transform: translateY(-5px); */
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
}

.my-avatar-card {
  background: #23232a;
  height: 150px;
  color: #fff;
}

.my-avatar-card .avatar-image {
  width: 100%;
  height: 100px;
  object-fit: cover;
}

.create-avatar-card {
  background: #2a2a2a;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 150px;
  cursor: pointer;
  transition: all 0.3s ease;
  border: 1px solid #409eff;
}

.create-avatar-card:hover {
  box-shadow: 0 8px 30px rgba(64, 158, 255, 0.2);
}

.create-avatar-content {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
}

.create-icon {
  font-size: 36px;
  opacity: 0.8;
  margin-top: -8px;
}

.create-text {
  font-size: 14px;
  font-weight: 500;
}

.create-hint {
  font-size: 11px;
  color: #909399;
  margin-top: 6px;
  opacity: 0.8;
}

/* 下半部分样式 */
.bottom-section {
  background: #23232a;
  border-radius: 20px;
  padding: 32px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
  border: 1px solid #2a2a2a;
}

.section-title {
  font-size: 24px;
  font-weight: 600;
  color: #fff;
  margin: 0 0 24px 0;
  text-align: center;
  letter-spacing: 0.5px;
}

/* 右侧脚本编辑面板 */
.script-panel {
  width: 380px;
  background: #23232a;
  border-radius: 16px;
  padding: 24px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
  height: calc(100vh - 48px);
  position: sticky;
  top: 24px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: #fff;
}


.script-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.script-header h3 {
  font-size: 18px;
  font-weight: 600;
  color: #fff;
  margin: 0;
}

.script-textarea {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.script-textarea :deep(.el-textarea) {
  height: auto !important;
  display: flex;
  flex-direction: column;
}

.script-textarea :deep(.el-textarea__inner) {
  min-height: 600px !important;
  height: 600px !important;
  max-height: 600px !important;
  resize: none !important;
  background: #18181c;
  border: 1px solid #2a2a2a !important;
  color: #fff;
  box-shadow: none !important;
  line-height: 1.5;
  padding: 8px 12px;
}

.script-textarea :deep(.el-textarea__inner:focus) {
  border-color: #409eff;
}

.script-textarea :deep(.el-input__count) {
  background: transparent !important;
  color: #909399 !important;
  border: none !important;
  font-size: 12px !important;
  right: 8px !important;
  bottom: 8px !important;
}

.script-footer {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.letter-options {
  display: flex;
  justify-content: center;
  margin-bottom: 12px;
}

:deep(.letter-options .el-radio-button__inner) {
  background: #23232a !important;
  border: 1px solid #2a2a2a !important;
  color: #909399 !important;
  box-shadow: none !important;
  font-weight: 500 !important;
  font-size: 14px !important;
  padding: 8px 20px !important;
  border-radius: 4px !important;
  margin: 0 4px !important;
}

:deep(.letter-options .el-radio-button__inner:hover) {
  border-color: #409eff !important;
  color: #409eff !important;
  background: #2a2a2a !important;
}

:deep(.letter-options .el-radio-button.is-active .el-radio-button__inner) {
  background: #409eff !important;
  border-color: #409eff !important;
  color: #fff !important;
  box-shadow: none !important;
}

.voice-select,
.caption-select {
  width: 100%;
}

:deep(.caption-select .el-input__wrapper) {
  background: #18181c !important;
  box-shadow: 0 0 0 1px #2a2a2a !important;
  border: none !important;
}

:deep(.caption-select .el-input__wrapper:hover) {
  box-shadow: 0 0 0 1px #409eff !important;
}

:deep(.caption-select .el-input__wrapper.is-focus) {
  box-shadow: 0 0 0 1px #409eff !important;
}


.generate-btn {
  background: #409eff;
  border: none;
  border-radius: 12px;
  padding: 12px;
  padding-right: 80px !important;
  font-weight: 600;
  box-shadow: 0 4px 15px rgba(64, 158, 255, 0.2);
  position: relative;
}

.generate-btn:hover {
  background-color: #66b1ff;
  box-shadow: 0 4px 15px rgba(64, 158, 255, 0.4);
}

.points-text {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 12px;
  opacity: 1;
  padding-left: 12px;
  border-left: 1px solid rgba(255, 255, 255, 0.5);
}

/* 视频预览弹窗样式 */
:deep(.video-dialog .el-dialog) {
  background: #23232a;
  border-radius: 20px;
  border: 1px solid #2a2a2a;
}

:deep(.video-dialog .el-dialog__header) {
  background: #2a2a2a;
  border-radius: 20px 20px 0 0;
  padding: 20px 24px;
  border-bottom: 1px solid #32323a;
}

:deep(.video-dialog .el-dialog__title) {
  color: white;
  font-size: 18px;
  font-weight: 600;
}

:deep(.video-dialog .el-dialog__body) {
  padding: 24px;
}

.video-preview-container {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.video-wrapper {
  position: relative;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 16px;
  overflow: hidden;
}

.preview-video {
  width: 100%;
  height: auto;
  display: block;
}

.video-loading {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: white;
  font-size: 16px;
}

.video-info-card {
  background: #2a2a2a;
  border-radius: 16px;
  padding: 24px;
  color: #fff;
}

.info-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid #32323a;
}

.info-header h3 {
  margin: 0;
  color: #fff;
  font-size: 20px;
  font-weight: 600;
}

.info-content {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 24px;
}

.info-item {
  display: flex;
  align-items: center;
}

.info-item .label {
  color: #909399;
  font-size: 14px;
  min-width: 120px;
  font-weight: 500;
}

.info-item .value {
  color: #fff;
  font-size: 14px;
  flex: 1;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

/* 响应式设计 */
@media (max-width: 1200px) {
  .digital-human-generate {
    flex-direction: column;
  }
  
  .script-panel {
    width: 100%;
    height: auto;
    position: static;
  }
  
  .my-avatars-grid,
  .public-avatars-grid {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 20px;
  }
  
  .section-title {
    font-size: 20px;
  }
  
  .public-avatars-grid {
    max-height: 500px;
    gap: 16px;
  }
  
  .avatar-image,
  .avatar-video {
    height: 200px;
  }
}

.upload-wrapper {
  position: relative;
}

.file-input {
  display: none;
}

.preview-content {
  width: 100%;
  height: 100%;
  position: relative;
}

.preview-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 16px;
}

.preview-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s ease;
  border-radius: 16px;
}

.preview-content:hover .preview-overlay {
  opacity: 1;
}

.preview-actions {
  display: flex;
  gap: 12px;
}

.audio-upload-section {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #23232a;
  border-radius: 8px;
  padding: 24px;
  margin-bottom: 20px;
  color: #fff;
  border: 1px solid #2a2a2a;
}

.upload-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px;
  border: 2px dashed #2a2a2a;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  background: #18181c;
  color: #909399;
}

.upload-placeholder:hover {
  border-color: #409eff;
  background: #23232a;
}

.upload-text {
  margin-top: 16px;
  font-size: 16px;
}

.upload-hint {
  margin-top: 8px;
  font-size: 12px;
}

.audio-preview {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.audio-info {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #909399;
}

.audio-name {
  font-size: 14px;
  word-break: break-all;
}

.audio-player {
  width: 100%;
  background: #18181c;
  border-radius: 4px;
  padding: 8px;
}

.audio-actions {
  display: flex;
  justify-content: flex-end;
}

.voice-filter {
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  gap: 20px;
  background: #2a2a2a;
  padding: 24px;
  border-radius: 12px;
  border: 1px solid #32323a;
  flex-wrap: wrap;
}

.filter-row {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.filter-item {
  margin-right: 0 !important;
}

.filter-item:deep(.el-radio-group) {
  display: flex;
  gap: 0;
}

.voice-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 20px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 16px;
  background: #18181c;
  border-radius: 8px;
}

.voice-card {
  background: #23232a;
  border-radius: 8px;
  padding: 16px;
  cursor: pointer;
  transition: all 0.3s ease;
  border: 1px solid #2a2a2a;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: #fff;
}

.voice-card:hover {
  background: #2a2a2a;
  border-color: #409eff;
}

.voice-card.active {
  background: #2a2a2a;
  border-color: #409eff;
}

.voice-info {
  flex: 1;
}

.voice-name {
  font-size: 16px;
  font-weight: 500;
  color: #fff;
  margin-bottom: 8px;
}

.voice-tags {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* 音色选择弹窗样式 */
:deep(.voice-dialog) {
  background: transparent !important;
}

:deep(.voice-dialog .el-overlay) {
  background-color: rgba(0, 0, 0, 0.7) !important;
}

:deep(.voice-dialog .el-dialog) {
  background: #23232a;
  border: 1px solid #2a2a2a;
  border-radius: 12px;
  margin: 0 !important;
}

:deep(.voice-dialog .el-dialog__header) {
  background: #2a2a2a;
  margin: 0;
  padding: 20px;
  border-bottom: 1px solid #32323a;
}

:deep(.voice-dialog .el-dialog__title) {
  color: #fff;
  font-size: 18px;
  font-weight: 600;
}

:deep(.voice-dialog .el-dialog__body) {
  padding: 20px;
  background: #23232a;
  color: #fff;
}

:deep(.voice-dialog .el-dialog__footer) {
  background: #23232a;
  border-top: 1px solid #32323a;
  padding: 16px 20px;
}

:deep(.voice-dialog .el-dialog__headerbtn .el-dialog__close) {
  color: #909399;
}

:deep(.voice-dialog .el-dialog__headerbtn .el-dialog__close:hover) {
  color: #fff;
}

:deep(.voice-dialog .el-dialog__headerbtn) {
  top: 20px !important;
  right: 20px !important;
  width: 40px !important;
  height: 40px !important;
}

:deep(.voice-dialog .el-dialog__headerbtn .el-dialog__close) {
  color: #909399;
  font-size: 18px !important;
  width: 100% !important;
  height: 100% !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  border-radius: 8px !important;
  transition: all 0.3s ease !important;
}

:deep(.voice-dialog .el-dialog__headerbtn .el-dialog__close:hover) {
  color: #fff;
  background-color: rgba(255, 255, 255, 0.1) !important;
}

/* 语言选择框样式 */
.language-select {
  min-width: 220px !important;
}

/* 如果有动画关键帧，直接禁用 */
:deep(.el-radio-button),
:deep(.el-radio-button *) {
  animation: none !important;
  animation-duration: 0s !important;
  animation-delay: 0s !important;
  animation-iteration-count: 0 !important;
}

/* 重新添加基础样式但保持防变大 */
:deep(.el-radio-button__inner) {
  background-color: #23232a !important;
  border: 1px solid #2a2a2a !important;
  color: #909399 !important;
  box-shadow: none !important;
  font-weight: 500 !important;
  font-size: 14px !important;
  padding: 10px 20px !important;
  margin: 0 8px 0 0 !important;
  border-radius: 8px !important;
  /* 再次强调不变大 */
  transform: none !important;
  scale: 1 !important;
  zoom: 1 !important;
}

/* 悬停状态样式 */
:deep(.el-radio-button__inner:hover) {
  border-color: #409eff !important;
  color: #409eff !important;
  background-color: #2a2a2a !important;
  /* 再次强调不变大 */
  transform: none !important;
  scale: 1 !important;
  zoom: 1 !important;
}

/* 选中状态样式 */
:deep(.el-radio-button.is-active .el-radio-button__inner),
:deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
  background: linear-gradient(135deg, #409eff, #66b1ff) !important;
  border-color: #409eff !important;
  color: #ffffff !important;
  font-weight: 600 !important;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3) !important;
  /* 最重要的：选中时绝对不变大 */
  transform: none !important;
  scale: 1 !important;
  zoom: 1 !important;
  font-size: 14px !important;
  padding: 10px 20px !important;
  width: auto !important;
  height: auto !important;
}

/* 首尾按钮特殊样式 */
:deep(.el-radio-button:first-child .el-radio-button__inner) {
  margin-left: 0 !important;
  transform: none !important;
}

:deep(.el-radio-button:last-child .el-radio-button__inner) {
  margin-right: 0 !important;
  transform: none !important;
}

/* 🔥 最终解决方案 - 暴力重写Element Plus */
:deep(.voice-dialog .el-radio-button__inner),
:deep(.voice-dialog .el-radio-button__inner:hover),
:deep(.voice-dialog .el-radio-button__inner:focus),
:deep(.voice-dialog .el-radio-button__inner:active),
:deep(.voice-dialog .el-radio-button.is-active .el-radio-button__inner),
:deep(.voice-dialog .el-radio-button__orig-radio:checked + .el-radio-button__inner) {
  font-size: 14px !important;
  line-height: 1.4 !important;
  padding: 10px 20px !important;
  margin: 0 8px 0 0 !important;
  width: auto !important;
  height: auto !important;
  min-width: auto !important;
  min-height: auto !important;
  max-width: none !important;
  max-height: none !important;
  transform: none !important;
  -webkit-transform: none !important;
  -moz-transform: none !important;
  -ms-transform: none !important;
  scale: 1 !important;
  zoom: 1 !important;
  animation: none !important;
  transition: background-color 0.3s ease, border-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease !important;
}

/* 强制覆盖所有可能的Element Plus内部样式 */
:deep(.voice-dialog) .el-radio-button__inner,
:deep(.voice-dialog) .el-radio-button__inner:hover,
:deep(.voice-dialog) .el-radio-button__inner:focus,
:deep(.voice-dialog) .el-radio-button.is-active .el-radio-button__inner,
:deep(.voice-dialog) .el-radio-button__orig-radio:checked + .el-radio-button__inner {
  font-size: 14px !important;
  transform: none !important;
  scale: 1 !important;
  zoom: 1 !important;
  padding: 10px 20px !important;
}

/* 直接覆盖Element Plus可能的CSS变量 */
:deep(.voice-dialog) {
  --el-font-size-base: 14px !important;
  --el-radio-button-font-size: 14px !important;
}

/* 最后的杀手锏 - 用属性选择器 */
:deep(.voice-dialog) [class*="el-radio-button__inner"] {
  font-size: 14px !important;
  transform: none !important;
  scale: 1 !important;
  zoom: 1 !important;
  padding: 10px 20px !important;
  line-height: 1.4 !important;
}

/* 滚动条样式 */
.voice-grid::-webkit-scrollbar {
  width: 6px;
}

.voice-grid::-webkit-scrollbar-track {
  background: #18181c;
  border-radius: 3px;
}

.voice-grid::-webkit-scrollbar-thumb {
  background: #409eff;
  border-radius: 3px;
}

/* 加载更多样式 */
.loading-more {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  color: #909399;
  font-size: 14px;
  gap: 8px;
  background: #2a2a2a;
  border-radius: 8px;
  margin-top: 16px;
}

:deep(.loading-more .el-icon) {
  color: #409eff;
}

/* 搜索框和下拉框样式 */
:deep(.el-input__wrapper), :deep(.el-select__wrapper) {
  background-color: #18181c !important;
  box-shadow: 0 0 0 1px #2a2a2a !important;
  border: none !important;
}

:deep(.el-input__wrapper:hover), :deep(.el-select__wrapper:hover) {
  box-shadow: 0 0 0 1px #409eff !important;
}

:deep(.el-input__wrapper.is-focus), :deep(.el-select__wrapper.is-focus) {
  box-shadow: 0 0 0 1px #409eff !important;
}

.subtitle-select { display: none !important; }

/* 按钮样式统一 */
:deep(.el-button) {
  background-color: #23232a !important;
  border-color: #2a2a2a !important;

  &:hover {
  background-color: #2a2a2a !important;
  border-color: #409eff !important;
    color: #409eff !important;
  }
  
  &.is-active {
    background-color: #409eff !important;
    border-color: #409eff !important;
    color: #fff !important;
  }
}

:deep(.el-button--primary) {
  background-color: #409eff !important;
  border-color: #409eff !important;
}

:deep(.el-button--primary:hover) {
  background-color: #66b1ff !important;
  border-color: #66b1ff !important;
}

:deep(.el-button--danger) {
  background-color: #f56c6c !important;
  border-color: #f56c6c !important;
}

:deep(.el-button--danger:hover) {
  background-color: #f78989 !important;
  border-color: #f78989 !important;
}

/* 链接按钮样式 */
:deep(.el-button--link) {
  background-color: transparent !important;
  border-color: transparent !important;
  color: #409eff !important;
}

:deep(.el-button--link:hover) {
  color: #66b1ff !important;
}

:deep(.el-button--link.el-button--danger) {
  color: #f56c6c !important;
}

:deep(.el-button--link.el-button--danger:hover) {
  color: #f78989 !important;
}

/* 标签样式 */
:deep(.el-tag) {
  background-color: #23232a !important;
  border-color: #2a2a2a !important;
}

/* 人种筛选样式 */
.ethnicity-section {
  margin-bottom: 24px;
}

.section-subtitle {
  font-size: 16px;
  font-weight: 600;
  color: #fff;
  margin: 0 0 12px 0;
}

.ethnicity-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 8px;
}

.category-item {
  background: #1f1f1f;
  border: 1px solid #2c2c2c;
  border-radius: 8px;
  color: #e0e0e0;
  padding: 10px 24px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  user-select: none;
  position: relative;
  overflow: hidden;
}

.category-item:hover {
  border-color: #409eff;
  color: #409eff;
  background: #23232a;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
}

.category-item.active {
  background: linear-gradient(135deg, #409eff, #66b1ff);
  border-color: #409eff;
  color: #ffffff;
  box-shadow: 0 2px 12px rgba(64, 158, 255, 0.3);
  font-weight: 600;
}

.category-item.active::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0));
  pointer-events: none;
}

.category-item.disabled {
  background: #23232a;
  color: #666;
  border-color: #23232a;
  cursor: not-allowed;
  transform: none;
}

.category-item.disabled:hover {
  transform: none;
  box-shadow: none;
  border-color: #23232a;
  color: #666;
}

/* 公共数字人网格样式 */
.public-avatars-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 10px;
  max-height: 600px;
  overflow-y: auto;
  padding: 8px;
  border-radius: 12px;
}

.public-avatars-grid::-webkit-scrollbar {
  width: 10px;
}

.public-avatars-grid::-webkit-scrollbar-track {
  background: #18181c;
  border-radius: 5px;
}

.public-avatars-grid::-webkit-scrollbar-thumb {
  background: linear-gradient(45deg, #409eff, #66b1ff);
  border-radius: 5px;
}

.public-avatars-grid::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(45deg, #66b1ff, #409eff);
}

.avatar-item {
  position: relative;
  overflow: hidden;
  border-radius: 12px;
  cursor: pointer;
  transition: transform 0.3s ease;
}

.avatar-item:hover {
  transform: scale(1.02);
}

.avatar-image,
.avatar-video {
  width: 100%;
  height: 240px;
  object-fit: contain;
  border-radius: 12px;
  display: block;
  transition: opacity 0.3s ease;
  background: #18181c;
}

.avatar-video {
  background: #000;
}


/* 音频播放器样式 */
.audio-player {
  width: 100%;
  background: #18181c;
  border-radius: 4px;
  padding: 8px;
}

/* 试听按钮样式 */
.preview-btn {
  font-weight: 600 !important;
  letter-spacing: 1px !important;
  padding: 8px 16px !important;
  display: flex !important;
  align-items: center !important;
  gap: 4px !important;
}

.preview-btn :deep(.el-icon) {
  margin-right: 2px !important;
}

/* 按钮组样式 */
:deep(.el-button-group) {
  .el-button {
    background-color: #23232a !important;
    border-color: #2a2a2a !important;
    
    &:hover {
      background-color: #2a2a2a !important;
      border-color: #409eff !important;
      color: #409eff !important;
    }
    
    &.is-active {
      background-color: #409eff !important;
      border-color: #409eff !important;
      color: #fff !important;
    }
  }
}
</style> 